package plateau;

import java.util.Iterator;

import structureDeDonnee.Cell;
import structureDeDonnee.Matrice;
import structureDeDonnee.MatriceMyList;
import structureDeDonnee.Position;

/**
 * PlateauGeneral est une implémentation abstraite de plateau représentant la
 * configuration du jeu de la vie par une matrice contenant les cellules
 * vivantes.
 */
public abstract class PlateauGeneral implements Plateau {

	/**
	 * une matrice contenant la liste des cellules vivantes
	 */
	protected Matrice matrice;

	/**
	 * un tableau comprenant une liste des valeurs permetant à une cellule
	 * vivante de rester vivante à l'étape suivant
	 */
	protected int[] valeursDeSurvie;

	/**
	 * un tableau comprenant une liste des valeurs permetant à une cellule morte
	 * de devenir vivante à l'étape suivante
	 */
	protected int[] valeursDeNaissance;

	/**
	 * 
	 * @param matrice
	 *            une matrice contenant la liste des cellules vivantes
	 * @param valeursDeSurvie
	 *            un tableau comprenant une liste des valeurs permetant à une
	 *            cellule vivante de rester vivante à l'étape suivant
	 * @param valeursDeNaissance
	 *            un tableau comprenant une liste des valeurs permetant à une
	 *            cellule morte de devenir vivante à l'étape suivante
	 */
	public PlateauGeneral(Matrice matrice, int[] valeursDeSurvie,
			int[] valeursDeNaissance) {
		this.matrice = matrice;
		this.valeursDeSurvie = valeursDeSurvie;
		this.valeursDeNaissance = valeursDeNaissance;
	}

	@Override
	public Matrice etapeSuivante() {
		Matrice construct = new MatriceMyList();
		Matrice[] tab = new Matrice[9];
		for (int i = 0; i < 9; ++i) {
			tab[i] = new MatriceMyList();
		}
		//on parcoure les cellules vivantes de this
		Iterator<Cell> it = matrice.iterator();
		Cell c = null;
		while (it.hasNext()) {			c = it.next();
			ajouteCelluleMatricesVoisines( c, tab);
		}
		for (int i = 0; i < 9; ++i) {
			construct = construct.addAll(tab[i]);
		}
		this.matrice = determinationMatriceSuivante(construct);
		return this.matrice;
	}
	
	@Override
	public Matrice getMatrice() {
		return this.matrice;
	}

	/**
	 * Dit si les cellules de la matrice envoyé en paramètre ont la même
	 * position que les cellules du plateau à une translation prêt. Si oui donne
	 * le vecteur de translation.
	 * 
	 * @param m
	 *            matrice contenant la liste de cellules que l'on veux comparer
	 *            aux cellules du plateau
	 * @param p
	 *            si la fonction renvoit vrai, met à jour p de façon à ce qu'il
	 *            contienne les valeurs du vecteur de translation dans p.
	 * @return vrai si les cellules de la liste de cellules envoyé en paramêtre
	 *         ont la même position que les cellules du plateau à une
	 *         translation prêt
	 */
	@Override
	public abstract boolean estUneTranslation(Matrice matrice, Position p);

	@Override
	public abstract Plateau clone();

	@Override
	public abstract boolean afficher();

	/**
	 * recupere une matrice de cellule pondéré représentant le nombre de voisins
	 * vivant de chaque cellule de this (+9 si la cellule est elle même vivante)
	 * et renvoit une list myList contenant les cellules vivante de this à
	 * l'étape suivante
	 * 
	 * @param mat une matrice de cellule pondéré représentant le nombre de voisins
	 * vivant de chaque cellule de this (+9 si la cellule est elle même vivante)
	 * @return myList contenant les cellules vivante de this à
	 * l'étape suivante
	 */
	protected Matrice determinationMatriceSuivante(Matrice mat) {
		boolean vit;
		int i;
		Matrice construction = new MatriceMyList();
		Iterator<Cell> it = mat.iterator();
		while (it.hasNext()) {
			i = 0;
			Cell tmp = it.next();
			int poidsCellule = tmp.getPoids();
			vit = false;
			if (poidsCellule >= 9) { // la cellule était vivante au tour //
										// d'avant
				poidsCellule = poidsCellule % 9;
				while (i < valeursDeSurvie.length && !vit) {
					if (poidsCellule == valeursDeSurvie[i]) {
						// la cellule a le bon nombre de voisin pour
						// survivre
						vit = true;
						construction.add(new Cell(tmp.getPosition()));
					}
					i++;
				}
			} else {
				while (i < valeursDeNaissance.length && !vit) {
					if (poidsCellule == valeursDeNaissance[i]) {
						// la cellule a le bon nombre de voisin pour naitre
						vit = true;
						construction.add(new Cell(tmp.getPosition()));
					}
					i++;
				}
			}
		}
		return construction;
	}
	
	/**
	 * prend une cellules en paramètre et ajoute ces 8 voisins à 8 matrices 
	 * d'un tableau en leurs donnant un poids de 1 + une cellule à se propre position avec 
	 * un poids de 9
	 * @param tmp une cellules 
	 * @param tab un tableau comprenant 9 matrices
	 */
	protected abstract void ajouteCelluleMatricesVoisines(Cell tmp, Matrice[] tab);

}